:- module(constraint_pools).
:- export create_constraint_pool / 4.
:- export set_pool_item / 2.
:- export get_pool_item / 2.
:- export pool_is_empty / 1.
:- export get_all_pool_constraints / 2.
:- export set_typed_pool_constraints / 3.
:- export get_typed_pool_constraints / 3.
:- export collect_all_pool_constraints / 2.
:- export collect_typed_pool_constraints / 3.
:- export post_typed_pool_constraint / 3.
:- export is_constraint_pool / 1.
:- export create_constraint_pool / 3.
:- comment(summary, "Support for the creation of constraint pools").
:- comment(author, "Kish Shen and Joachim Schimpf, IC-Parc, Imperial College").
:- comment(copyright, "Imperial College London and Parc Technologies").
:- comment(date, "$Date").
:- comment(desc, html("<P>\n    This library contains support for constraint pools. Constraint\n    pools are a way to have several instances of a constraint solver.\n</P><P>\n    A constraint pool is an Eclipse module. It exports a number of\n    predicates (often constraint predicates) which are specified when\n    the pool is created. The constraint pool does not implement these\n    predicates (constraints) itself, but simply forwards every predicate\n    call, or stores the calls, annotated with the pool name.\n</P>\n")).
:- comment(collect_all_pool_constraints / 2, [summary : "Collect all currently stored constraints in Pool", amode : collect_all_pool_constraints(+, -), args : ["Pool" : "Atom", "Constraints" : "Variable, returns list of callable terms"], desc : html("\n    Constraints is unified with a list of all currently stored constraints\n    in Pool, regardless of their type.  An empty list is returned if the\n    pool was already empty.  The pool store is emptied completely.\n    This modification is backtrackable.\n    "), see_also : [pool_is_empty / 1, get_all_pool_constraints / 2, collect_typed_pool_constraints / 3]]).
:- comment(collect_typed_pool_constraints / 3, [summary : "Collect all currently stored constraints of type Type in Pool", amode : collect_typed_pool_constraints(+, +, -), args : ["Pool" : "Atom", "Type" : "Integer", "Constraints" : "Variable, returns list of callable terms"], desc : html("\n    Constraints is unified with a list of all currently stored\n    constraints of type Type in Pool.  An empty list is returned if\n    the pool was already empty for this type.  The pool store for type\n    Type is emptied.  This modification is backtrackable.\n    "), see_also : [pool_is_empty / 1, get_typed_pool_constraints / 3, collect_all_pool_constraints / 2]]).
:- comment(create_constraint_pool / 3, [summary : "Create a \"constraint pool\" module", amode : create_constraint_pool(+, +, ++), args : ["PoolName" : "Atom - the name of the pool to create", "NTypes" : "Integer - the number of constraint types", "SpecList" : "List of terms of the form Atom/Integer->Spec"], desc : html("<P>\n\tCreate a special type of module, called a \"constraint pool\".\n</P><P>\n\tThe module will contain:\n\t<UL>\n\t<LI>simple definitions for the predicates listed in SpecList.\n\t    These definitions will just store or forward every call.\n\t<LI>a logical store which can be used to store and retrieve\n\t    constraints, indexed by pool name and type. NTypes is the number\n\t    of different constraint types that this pool will support.\n\t<LI>a logical store for one additional data item, for example\n\t    a solver handle.\n\t</UL>\n</P><P>\n\tThe possible specifications in SpecList are:\n\t<DL>\n\t<DT>N/A -&gt; store_as(Type)</DT><DD>\n\t    will generate a definition for the predicate N/A such that every\n\t    call to N/A will be stored in the pool for the given Type.\n\t    </DD>\n\t<DT>N/A -&gt; ImplN/ImplA</DT><DD>\n\t    will generate a definition for the predicate N/A such that every\n\t    call to N/A gets augmented with an additional argument (the pool\n\t    name), and mapped into a call to the implementation predicate\n\t    ImplN/ImplA. The implementation predicate must be visible from\n\t    where create_constraint_pool/3 is invoked.  The implementation\n\t    predicate's arity ImplA must be one higher than the the arity A\n\t    of the newly defined predicate.\n\t    </DD>\n\t</DL>\n</P><P>\n\tSince a pool is a module, the pool name should normally not refer\n\tto an existing module. If it does, the existing module gets augmented\n\twith the pool predicates and pool stores.\n</P>\n    "), eg : "    % We assume the implementation predicate:\n    d(Data, Pool) :- writeln(d(Data, Pool)).\n\n    % Create the pool:\n    ?- create_constraint_pool(pool, 1, [c/2->store_as(1),d/1->d/2]).\n    Yes (0.00s cpu)\n\n    % Call the just created pool constraint d/1,\n    % which leads to d/2 being invoked:\n    ?- pool:d(hello).\n    d(hello, pool)\n    Yes (0.00s cpu)\n\n    % Call the just created pool constraint c/2,\n    % which will be stored. Then retrieve the store:\n    ?- pool:c(a,b), collect_all_pool_constraints(pool, C).\n    C = [c(a, b)]\n    Yes (0.00s cpu)\n    ", see_also : [is_constraint_pool / 1, pool_is_empty / 1, post_typed_pool_constraint / 3, collect_typed_pool_constraints / 3, collect_all_pool_constraints / 2, set_pool_item / 2, get_pool_item / 2]]).
:- comment(get_all_pool_constraints / 2, [summary : "Get all currently stored constraints Pool", amode : get_all_pool_constraints(+, -), args : ["Pool" : "Atom", "Constraints" : "Variable, returns list of callable terms"], desc : html("\n    Constraints is unified with a list of all currently stored constraints\n    in Pool, regardless of their type. The pool itself is not changed.\n    An empty list is returned if the pool is empty.\n    "), see_also : [collect_all_pool_constraints / 2, get_typed_pool_constraints / 3]]).
:- comment(get_pool_item / 2, [summary : "Associate a term Item with the pool Pool", amode : get_pool_item(+, -), args : ["Pool" : "Atom", "Item" : "Variable, returns term"], desc : html("\n    Retrieve the 'pool item', i.e. the term associated with the\n    pool using set_pool_item/2. This could for example be a solver\n    handle.  The pool is not modified.\n    "), see_also : [create_constraint_pool / 3, set_pool_item / 2]]).
:- comment(get_typed_pool_constraints / 3, [summary : "Get all currently stored constraints of type Type in Pool", amode : get_typed_pool_constraints(+, +, -), args : ["Pool" : "Atom", "Type" : "Integer", "Constraints" : "Variable, returns list of callable terms"], desc : html("\n    Constraints is unified with a list of all currently stored constraints\n    of type Type in Pool. The pool itself is not changed.\n    An empty list is returned if the pool is empty for this type.\n    "), see_also : [collect_typed_pool_constraints / 3, get_all_pool_constraints / 2]]).
:- comment(is_constraint_pool / 1, [summary : "Check whether Pool is a constraint pool", amode : is_constraint_pool(+), args : ["Pool" : "Atom"], desc : html("\n    Succeeds of Pool is a constraint pool that has been created earlier\n    using create_constraint_pool/3.\n    "), eg : "    ", see_also : [create_constraint_pool / 3]]).
:- comment(pool_is_empty / 1, [summary : "Check whether Pool is an empty constraint pool", amode : pool_is_empty(+), args : ["Pool" : "Atom"], desc : html("\n    Succeeds of Pool is an empty constraint pool, i.e. has no constraints\n    stored.\n    "), eg : "    ", see_also : [create_constraint_pool / 3, post_typed_pool_constraint / 3, collect_typed_pool_constraints / 3, collect_all_pool_constraints / 2, get_typed_pool_constraints, set_typed_pool_constraints / 3, get_all_pool_constraints / 2]]).
:- comment(post_typed_pool_constraint / 3, [summary : "Stores the term Constraint in Pool's constraint store as type Type", amode : post_typed_pool_constraint(+, +, +), args : ["Pool" : "Atom", "Type" : "Integer", "Constraint" : "Callable Term"], desc : html("\n    Stores the term Constraint in Pool's constraint store as type Type.\n    Constraint is not interpreted in any way, it is just stored in order\n    to be retrieved later using one of the retrieval predicates.\n    "), eg : "    ?- create_constraint_pool(p, 3, []).\n    Yes (0.09s cpu)\n\n    ?- post_typed_pool_constraint(p, 1, foo(one)),\n\t    post_typed_pool_constraint(p, 2, bar(two)),\n\t    post_typed_pool_constraint(p, 1, baz(three)),\n\t    get_typed_pool_constraints(p, 1, C1),\n\t    get_typed_pool_constraints(p, 2, C2).\n\t    get_typed_pool_constraints(p, 3, C3).\n\n    C1 = [baz(three), foo(one)]\n    C2 = [bar(two)]\n    C3 = []\n    Yes (0.00s cpu)\n    ", see_also : [collect_typed_pool_constraints / 3, collect_all_pool_constraints / 2, get_typed_pool_constraints, set_typed_pool_constraints / 3, get_all_pool_constraints / 2]]).
:- comment(set_pool_item / 2, [summary : "Associate a term Item with the pool Pool", amode : set_pool_item(+, +), args : ["Pool" : "Atom", "Item" : "Arbitrary term"], desc : html("\n    An arbitrary term (for example a solver handle) is associated with the\n    pool Pool, in order to be retrieved later using get_pool_item/2.\n    The modification to the pool is backtrackable.\n    "), eg : "    ?- create_constraint_pool(p, 0, []).\n    Yes (0.08s cpu)\n\n    ?- set_pool_item(p, sample_item), get_pool_item(p,X).\n    X = sample_item\n    Yes (0.00s cpu)\n    ", see_also : [create_constraint_pool / 3, get_pool_item / 2]]).
:- comment(set_typed_pool_constraints / 3, [summary : "Replace the stored constraints for type Type", amode : set_typed_pool_constraints(+, +, +), args : ["Pool" : "Atom", "Type" : "Integer", "Constraints" : "List of callable Terms"], desc : html("\n    The constraint store of pool Pool for type Type is forgotten and\n    replaced with the list of constraints Constraints.  This\n    modification is backtrackable.\n    "), eg : "    ", see_also : [collect_typed_pool_constraints / 3, get_typed_pool_constraints / 3]]).
:- comment(create_constraint_pool / 4, hidden).
